/*
 * Copyright (C) 2005 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_STRONG_POINTER_H
#define ANDROID_STRONG_POINTER_H

#include "../cutils/atomic.h"


#include <stdint.h>
#include <sys/types.h>
#include <stdlib.h>

// ---------------------------------------------------------------------------
namespace android {

    template<typename T>
    class wp;

// ---------------------------------------------------------------------------

#define COMPARE(_op_)                                           \
inline bool operator _op_ (const sp<T>& o) const {              \
    return m_ptr _op_ o.m_ptr;                                  \
}                                                               \
inline bool operator _op_ (const T* o) const {                  \
    return m_ptr _op_ o;                                        \
}                                                               \
template<typename U>                                            \
inline bool operator _op_ (const sp<U>& o) const {              \
    return m_ptr _op_ o.m_ptr;                                  \
}                                                               \
template<typename U>                                            \
inline bool operator _op_ (const U* o) const {                  \
    return m_ptr _op_ o;                                        \
}                                                               \
inline bool operator _op_ (const wp<T>& o) const {              \
    return m_ptr _op_ o.m_ptr;                                  \
}                                                               \
template<typename U>                                            \
inline bool operator _op_ (const wp<U>& o) const {              \
    return m_ptr _op_ o.m_ptr;                                  \
}

// ---------------------------------------------------------------------------

    template<typename T>
    class sp {
    public:
        inline sp() : m_ptr(0) {}

        sp(T *other);

        sp(const sp<T> &other);

        template<typename U>
        sp(U *other);

        template<typename U>
        sp(const sp<U> &other);

        ~sp();

        // Assignment

        sp &operator=(T *other);

        sp &operator=(const sp<T> &other);

        template<typename U>
        sp &operator=(const sp<U> &other);

        template<typename U>
        sp &operator=(U *other);

        //! Special optimization for use by ProcessState (and nobody else).
        void force_set(T *other);

        // Reset

        void clear();

        // Accessors

        inline T &operator*() const { return *m_ptr; }

        inline T *operator->() const { return m_ptr; }

        inline T *get() const { return m_ptr; }

        // Operators

        COMPARE(==)

        COMPARE(!=)

        COMPARE(>)

        COMPARE(<)

        COMPARE(<=)

        COMPARE(>=)

    private:
        template<typename Y> friend
        class sp;

        template<typename Y> friend
        class wp;

        void set_pointer(T *ptr);

        T *m_ptr;
    };

#undef COMPARE

// ---------------------------------------------------------------------------
// No user serviceable parts below here.

    template<typename T>
    sp<T>::sp(T *other)
            : m_ptr(other) {
        if (other)
            other->incStrong(this);
    }

    template<typename T>
    sp<T>::sp(const sp<T> &other)
            : m_ptr(other.m_ptr) {
        if (m_ptr)
            m_ptr->incStrong(this);
    }

    template<typename T>
    template<typename U>
    sp<T>::sp(U *other)
            : m_ptr(other) {
        if (other)
            ((T *) other)->incStrong(this);
    }

    template<typename T>
    template<typename U>
    sp<T>::sp(const sp<U> &other)
            : m_ptr(other.m_ptr) {
        if (m_ptr)
            m_ptr->incStrong(this);
    }

    template<typename T>
    sp<T>::~sp() {
        if (m_ptr)
            m_ptr->decStrong(this);
    }

    template<typename T>
    sp<T> &sp<T>::operator=(const sp<T> &other) {
        T *otherPtr(other.m_ptr);
        if (otherPtr)
            otherPtr->incStrong(this);
        if (m_ptr)
            m_ptr->decStrong(this);
        m_ptr = otherPtr;
        return *this;
    }

    template<typename T>
    sp<T> &sp<T>::operator=(T *other) {
        if (other)
            other->incStrong(this);
        if (m_ptr)
            m_ptr->decStrong(this);
        m_ptr = other;
        return *this;
    }

    template<typename T>
    template<typename U>
    sp<T> &sp<T>::operator=(const sp<U> &other) {
        T *otherPtr(other.m_ptr);
        if (otherPtr)
            otherPtr->incStrong(this);
        if (m_ptr)
            m_ptr->decStrong(this);
        m_ptr = otherPtr;
        return *this;
    }

    template<typename T>
    template<typename U>
    sp<T> &sp<T>::operator=(U *other) {
        if (other)
            ((T *) other)->incStrong(this);
        if (m_ptr)
            m_ptr->decStrong(this);
        m_ptr = other;
        return *this;
    }

    template<typename T>
    void sp<T>::force_set(T *other) {
        other->forceIncStrong(this);
        m_ptr = other;
    }

    template<typename T>
    void sp<T>::clear() {
        if (m_ptr) {
            m_ptr->decStrong(this);
            m_ptr = 0;
        }
    }

    template<typename T>
    void sp<T>::set_pointer(T *ptr) {
        m_ptr = ptr;
    }

}; // namespace android

// ---------------------------------------------------------------------------

#endif // ANDROID_STRONG_POINTER_H
